﻿/*Cat Lyons     CS4100      Spring 2011     Al Brouillette*/

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Compiler_Phase_3
{
    public class LexicalAnalyzer
    {
        #region FIELDS
        string filePath;      //Holds the name of the file that is being parsed
        string line;                      //Holds the current line being parsed
        static StreamReader file;                             //Reader for file
        bool echo;                    //If true, execute echo printing commands
        Token nextToken;                 //Holds the value of just-parsed token
        SymbolTable symbolTable;  //Symbol Table for loading numbers and idents
        TokenTable oneCharTokenTable;          //Holds the one char token table
        TokenTable twoCharTokenTable;          //Holds the two char token table
        TokenTable reserveTokenTable;      //Holds the reserve word token table
        MnemonicTable m;                                //Holds mnemonics table
        string lexeme;                          //Holds the value of the lexeme
        int index;                //Points to current char location in the line
        bool endOfFile;       //Set to true when the end of the file is reached
        int lineNumber;                     //Tracks the number of lines parsed

        const int ONESIZE = 18;                     //Number of one-char tokens
        const int TWOSIZE = 5;                      //Number of two-char tokens
        const int RESSIZE = 35;                 //Number of reserve word tokens
        #endregion

        /*--------------------------------------------------------------------|
         * Constructor takes a file name as a string, and bool value of echo  |
         * ------------------------------------------------------------------*/
        public LexicalAnalyzer(string thisFile, bool echo)
        {
            filePath = thisFile;                            //Set the file name
            file = new StreamReader(filePath);    //Initialize the StreamReader
            symbolTable = new SymbolTable();          //Initialize Symbol Table
            m = new MnemonicTable();                    //Create Mnemonic Table
            InitializeMnemonic();                           //Initialize values
            oneCharTokenTable = new TokenTable(ONESIZE, m); //Init. Token Table
            twoCharTokenTable = new TokenTable(TWOSIZE, m); //Init. token Table
            reserveTokenTable = new TokenTable(RESSIZE, m); //Init. Token Table
            InitializeOneCharTable();                     //Set values in table
            InitializeTwoCharTable();                     //Set values in table
            InitializeReserveTable();                     //Set values in table
            this.echo = echo;                                  //Set Echo value
            index = 0;              //Initialize index to first index in string
            lexeme = null;                                  //Initialize lexeme
            endOfFile = false;               //Initialize the end of file check
            lineNumber = 0;                              //Set line number to 0
        }
        /*--------------------------------------------------------------------|
         * InitizlizeOneCharTable initializes the one char token table to     |
         * given values.                                                      |
         * ------------------------------------------------------------------*/
        public void InitializeOneCharTable()
        {
            oneCharTokenTable.AddToken("+", 10);
            oneCharTokenTable.AddToken("=", 11);
            oneCharTokenTable.AddToken("*", 12);
            oneCharTokenTable.AddToken("-", 13);
            oneCharTokenTable.AddToken("#", 14);
            oneCharTokenTable.AddToken("<", 15);
            oneCharTokenTable.AddToken("/", 16);
            oneCharTokenTable.AddToken(">", 17);
            oneCharTokenTable.AddToken("&", 18);
            oneCharTokenTable.AddToken(".", 19);
            oneCharTokenTable.AddToken(",", 20);
            oneCharTokenTable.AddToken(";", 21);
            oneCharTokenTable.AddToken("(", 22);
            oneCharTokenTable.AddToken(")", 23);
            oneCharTokenTable.AddToken("~", 24);
            oneCharTokenTable.AddToken("[", 25);
            oneCharTokenTable.AddToken("]", 26);
            oneCharTokenTable.AddToken("|", 27);
        }
        /*--------------------------------------------------------------------|
         * InitizlizeTwoCharTable initializes the two char token table to     |
         * given values.                                                      |
         * ------------------------------------------------------------------*/
        public void InitializeTwoCharTable()
        {
            twoCharTokenTable.AddToken("<>", 14);
            twoCharTokenTable.AddToken(":=", 30);
            twoCharTokenTable.AddToken("<=", 32);
            twoCharTokenTable.AddToken(">=", 33);
            twoCharTokenTable.AddToken("..", 34);
        }
        /*--------------------------------------------------------------------|
         * InitizlizeReserveTable initializes the two char token table to     |
         * given values.                                                      |
         * ------------------------------------------------------------------*/
        public void InitializeReserveTable()
        {
            reserveTokenTable.AddToken("AND", 18);
            reserveTokenTable.AddToken("ARRAY", 40);
            reserveTokenTable.AddToken("BEGIN", 41);
            reserveTokenTable.AddToken("BY", 42);
            reserveTokenTable.AddToken("CASE", 43);
            reserveTokenTable.AddToken("CONST", 44);
            reserveTokenTable.AddToken("DO", 45);
            reserveTokenTable.AddToken("ELSE", 46);
            reserveTokenTable.AddToken("END", 47);
            reserveTokenTable.AddToken("EXIT", 48);
            reserveTokenTable.AddToken("FOR", 49);
            reserveTokenTable.AddToken("FROM", 50);
            reserveTokenTable.AddToken("IF", 51);
            reserveTokenTable.AddToken("IN", 52);
            reserveTokenTable.AddToken("LOOP", 53);
            reserveTokenTable.AddToken("MODULE", 54);
            reserveTokenTable.AddToken("NOT", 24);
            reserveTokenTable.AddToken("OF", 56);
            reserveTokenTable.AddToken("OR", 27);
            reserveTokenTable.AddToken("PROCEDURE", 58);
            reserveTokenTable.AddToken("RECORD", 59);
            reserveTokenTable.AddToken("REPEAT", 60);
            reserveTokenTable.AddToken("RETURN", 61);
            reserveTokenTable.AddToken("THEN", 62);
            reserveTokenTable.AddToken("TO", 63);
            reserveTokenTable.AddToken("TYPE", 64);
            reserveTokenTable.AddToken("UNTIL", 65);
            reserveTokenTable.AddToken("VAR", 66);
            reserveTokenTable.AddToken("WHILE", 67);
            reserveTokenTable.AddToken("WITH", 68);
            reserveTokenTable.AddToken("REAL", 80);
            reserveTokenTable.AddToken("INTEGER", 85);
            reserveTokenTable.AddToken("STRING", 90);
            reserveTokenTable.AddToken("LABEL", 69);
            reserveTokenTable.AddToken("COLON", 28);
        }
        /*--------------------------------------------------------------------|
         * GetNextToken: Iterates through the current line, getting a new line|
         * when necessary, to find the next token in the file.                |
         * ------------------------------------------------------------------*/
        /*--------------------------------------------------------------------|
         * Initialize Mnemonic sets the values of the mnemonic table with     |
         * given codes.                                                       |
         * ------------------------------------------------------------------*/
        public void InitializeMnemonic()
        {
            #region MNEMONIC TABLE DEFINITION
            m.AddMnemonic(1, "IDNT", "Identifier");
            m.AddMnemonic(2, "RLNM", "Real Number");
            m.AddMnemonic(3, "INTN", "Integer Number");
            m.AddMnemonic(4, "STRN", "String");
            m.AddMnemonic(10, "ADD", "Add");
            m.AddMnemonic(11, "EQUL", "Equality");
            m.AddMnemonic(12, "MULT", "Multiply");
            m.AddMnemonic(13, "SUB", "Subtract");
            m.AddMnemonic(14, "NOEQ", "Not Equal");
            m.AddMnemonic(15, "LSTN", "Less Than");
            m.AddMnemonic(16, "DIV", "Divide");
            m.AddMnemonic(17, "GRTN", "Greater Than");
            m.AddMnemonic(18, "AND", "And");
            m.AddMnemonic(19, "DECM", "Decimal");
            m.AddMnemonic(20, "COMA", "Comma");
            m.AddMnemonic(21, "SEMI", "Semi-colon");
            m.AddMnemonic(22, "LPRN", "Left Parenthesis");
            m.AddMnemonic(23, "RPRN", "Right Parenthesis");
            m.AddMnemonic(24, "NOT", "Not");
            m.AddMnemonic(25, "LBRK", "Left Bracket");
            m.AddMnemonic(26, "RBRK", "Right Bracket");
            m.AddMnemonic(27, "OR", "Or");
            m.AddMnemonic(30, "ASGN", "Assign");
            m.AddMnemonic(32, "LTEQ", "Less Than or Equal");
            m.AddMnemonic(33, "GTEQ", "Greater Than or Equal");
            m.AddMnemonic(34, "ARRN", "Array Range");
            m.AddMnemonic(40, "ARAY", "Array");
            m.AddMnemonic(41, "BEGN", "Begin");
            m.AddMnemonic(42, "BY", "By");
            m.AddMnemonic(43, "CASE", "Case");
            m.AddMnemonic(44, "CNST", "Constant");
            m.AddMnemonic(45, "DO", "Do");
            m.AddMnemonic(46, "ELSE", "Else");
            m.AddMnemonic(47, "END", "End");
            m.AddMnemonic(48, "EXIT", "Exit");
            m.AddMnemonic(49, "FOR", "For");
            m.AddMnemonic(50, "FROM", "From");
            m.AddMnemonic(51, "IF", "If");
            m.AddMnemonic(52, "IN", "In");
            m.AddMnemonic(53, "LOOP", "Loop");
            m.AddMnemonic(54, "MDLE", "Module");
            m.AddMnemonic(56, "OF", "Of");
            m.AddMnemonic(58, "PRCD", "Procedure");
            m.AddMnemonic(59, "RCRD", "Record");
            m.AddMnemonic(60, "REPT", "Repeat");
            m.AddMnemonic(61, "RTRN", "Return");
            m.AddMnemonic(62, "THEN", "Then");
            m.AddMnemonic(63, "TO", "To");
            m.AddMnemonic(64, "TYPE", "Type");
            m.AddMnemonic(65, "UNTL", "Until");
            m.AddMnemonic(66, "VAR", "Variable");
            m.AddMnemonic(67, "WHLE", "While");
            m.AddMnemonic(68, "WITH", "With");
            m.AddMnemonic(80, "REAL", "Real");
            m.AddMnemonic(85, "INT", "Integer");
            m.AddMnemonic(90, "STRN", "String");
            m.AddMnemonic(99, "INVD", "Invalid");
            m.AddMnemonic(69, "LABL", "Label");
            m.AddMnemonic(28, "COLN", "Colon");
            #endregion
        }
        public void GetNextToken()
        {
            nextToken = null;   /*Set nextToken to null so if comment, previous
                                 * token is not returned again.*/
            if (line == null)                            //If the line is empty
            {
                GetLine();                                     //Get a new line
            }

                if (line != null && line.Length > 0)
                {
                    index = 0;          //Reset char index to beginning of line
                    SkipWhiteSpace();           //Find next non-whitespace char

                    //Check the first character, and call methoods based on val
                    #region IS A COMMENT
                    if (GetChar(index, line) == '{')           //If {} delimited comment
                    {                                 //STATE DIAGRAM BRANCH #1
                        IsComment(1);
                    }         //'1' is arbitrary denotation of delimiter option
                    else if (GetChar(index, line) == '(' && 
                        GetChar(index + 1, line) == '*')
                    {      //If (**) delimited comment; STATE DIAGRAM BRANCH #2
                        IsComment(2);
                    }         //'2' is arbitrary denotation of delimiter option
                    #endregion
                    
                    #region IS A STRING
                    else if (GetChar(index, line) == '\'')//If '' delimited str
                    {                                 //STATE DIAGRAM BRANCH #3
                        IsString(1);    //'1' is arbitrary delimiter denotation
                    }
                    else if (GetChar(index, line) == '\"')
                    {                                 //STATE DIAGRAM BRANCH #4
                        IsString(2);    //'2' is arbitrary delimiter denotation
                    }
                    #endregion

                    #region IS ONE-CHAR OR TWO-CHAR TOKEN
                    else if ((index + 1) != line.Length &&
                        Char.Equals(GetChar(index, line), '<') &&
                        Char.Equals(GetChar(index, line), ':') &&
                        Char.Equals(GetChar(index, line), '>') &&
                        Char.Equals(GetChar(index, line), '.'))
                    {   /*if two non-letter/non-digit chars in a row, and first
                         * char starts two-char token. Checking against 2-char 
                         * tokens directly prevents errors if a one-char token 
                         * precedes a string or comment demlimiter.*/
                                               //STATE DIAGRAM BRANCH #5 AND #6
                        IsTwoChar();   /* Run Two-Char logic to see if two char
                                     * token, or two one-char tokens in a row*/
                    }
                    else if (!Char.IsLetterOrDigit(GetChar(index, line)))
                                                                  //If one-char
                    {                                 //STATE DIAGRAM BRANCH #6
                        IsOneChar();                           //Call IsOneChar
                    }
                    #endregion

                    #region IS NUMBER
                    else if (Char.IsDigit(GetChar(index, line)))    
                                                           //If char is a digit
                    {                         //STATE DIAGRAM BRANCH #7 --> #11
                        IsNumber();                             //Call IsNumber
                    }
                    #endregion

                    #region IS ALPHA
                    else if (Char.IsLetter(GetChar(index, line)))  
                                                          //If char is a letter
                    {                          //STATE DIAGRAM BRANCH #7 --> #8
                        IsAlpha();
                    }
                    #endregion

                    AdvanceLine();             //Clear line to next token point
                }
            }
        /*--------------------------------------------------------------------|
         * SkipWhiteSpace: Iterates through file, stripping whitespace until  |
         * non-whitespace char is found.                                      |
         * ------------------------------------------------------------------*/
        private void SkipWhiteSpace()
        {
            while (line.Length == 0 || Char.IsWhiteSpace(GetChar(index, line)))
            {                //while line is empty, or if line[0] is whitespace
                if (line.Length != 0)                //if the line is not empty
                {
                    if (Char.Equals(GetChar(index, line), null) &&
                        Char.IsWhiteSpace(GetChar(index, line)))
                    {                                        //if line is empty
                        GetLine();                          //Get the next line
                    }
                    else
                    {
                        if (index < line.Length - 1)   //if not at end of array
                        {
                            index = index + 1;                //increment index
                        }
                        else                            //if at end of the line
                        {
                            GetLine();                          //Get next line
                        }
                    }
                }
            }
        }
        /*--------------------------------------------------------------------|
         * AdvanceLine: Clears line of most recently obtained token           |
         * ------------------------------------------------------------------*/
        private void AdvanceLine()
        {
            if (line != null && index < line.Length)   //not null, index valid
            {
                string temp = null;   //create a temp string to hold new value
                for (int i = index; i < line.Length; i++)//while chars in line
                {
                    temp = temp + GetChar(i, line);      //move them into temp
                }
                line = temp;                           //set line to new value
                index = 0;                      //reset index to start of line
            }
            if (line != null && index >= line.Length)//if index > end of line
            {
                line = null;                              //line is now empty
            }
        }
        /*--------------------------------------------------------------------|
         * IsAlpha: When token starts with a letter, determines if identifier |
         * or reserve word.                                                   |
         * ------------------------------------------------------------------*/
        private void IsAlpha()
        {
            lexeme = null;                                       //reset lexeme
            while (index < line.Length && index < 30 &&
                Char.IsLetterOrDigit(GetChar(index, line)))
            {                            //index valid, char is letter or digit
                                                      //STATE DIAGRAM BRANCH #7
                lexeme = lexeme + GetChar(index, line);//fill lexeme with value
                index++;                         //increment index to next char
            }
            while(index < line.Length && Char.IsLetterOrDigit(GetChar(index, line)))
            {
                index++;
            }
            int code;                                     //token code variable
            code = reserveTokenTable.CheckExists(lexeme);//does the token exist
            if (code == -1)                                            //if not
            {                                        //STATE DIAGRAM BRANCH #10
                nextToken = new Token(lexeme, 1, m);       //must be identifier
            }
            else                                             //if it does exist
            {                                         //STATE DIAGRAM BRANCH #9
                nextToken = new Token(lexeme, code, m);      //Is reserved word
            }
            if (nextToken.TokenCode == 1)  //If identifier, add to symbol table
            {
                nextToken.STableLoc = symbolTable.AddSymbol(lexeme, 1, 1);
            }
        }
        /*--------------------------------------------------------------------|
         * IsTwoChar: If a two-char lexeme (which starts with valid first char|
         * for two-char tokens) is a token, set it. If not, must be two one   |
         * char tokens in a row, and call IsOneChar logic.                    |
         * ------------------------------------------------------------------*/
        private void IsTwoChar()
        {
            lexeme = null;                                       //Clear lexeme
            int code;                                     //token code variable
            lexeme = lexeme + GetChar(index, line) + GetChar(index + 1, line);
                                                            //lexeme is 2-chars
            code = twoCharTokenTable.CheckExists(lexeme);   //check if two-char
            if (code != -1)                 //If exists, must be two-char token
            {                                 //STATE DIAGRAM BRANCH #5 --> #14
                nextToken = new Token(lexeme, code, m);     //Create Next Token
                index = index + 2;              //Set index to char after token
            }
            else                 //Not found, must be treated as one char token
            {                                         //STATE DIAGRAM BRANCH #6
                IsOneChar();                              //Call one char logic
            }
        }
        /*--------------------------------------------------------------------|
         * IsOneChar: Handles logic for if a nonletter/nondigit token is      |
         * defined as a one-char token. If token is not defined, sets token   |
         * to 99 to show invalid character entry.                             |
         * ------------------------------------------------------------------*/
        private void IsOneChar()
        {
            lexeme = null;                                       //Clear lexeme
            int code;                                     //token code variable
            lexeme = lexeme + GetChar(index, line);     //load char into lexeme
            code = oneCharTokenTable.CheckExists(lexeme);    //Check if defined
            if (code == -1)                           //If token is NOT defined
            {
                code = 99;                         //Set code to Invalid option
            }
            index++;                         //Move pointer to char after token
            nextToken = new Token(lexeme, code, m);          //Create nextToken
        }
        /*--------------------------------------------------------------------|
         * IsNumber checks if token is a valid real or integer entry.         |
         * ------------------------------------------------------------------*/
        private void IsNumber()
        {
            lexeme = null;                                       //Clear Lexeme
            int code;
            while (index < line.Length && index < 30 &&
                Char.IsDigit(GetChar(index, line)))//While index valid & a digt
            {                                        //STATE DIAGRAM BRANCH #11
                lexeme = lexeme + GetChar(index, line);      //move into lexeme
                index++;
            }
            if (index < line.Length && Char.Equals(GetChar(index, line), '.') 
                && (index + 1) < line.Length 
                && Char.IsDigit(GetChar(index + 1, line)))
            {                //If number has valid placement of a decimal point
                                                     //STATE DIAGRAM BRANCH #13
                lexeme = lexeme + GetChar(index, line); //add decimal to lexeme
                index++;                              //move index to next char
                while (index < line.Length 
                    && Char.IsDigit(GetChar(index, line)))
                {                                       //while char is a digit
                    lexeme = lexeme + GetChar(index, line);//put it into lexeme
                    index++;                                //Move to next char
                }
                #region SCALE FACTOR
                if (index < line.Length 
                    && Char.Equals(GetChar(index, line), 'e') 
                    || index < line.Length 
                    && Char.Equals(GetChar(index, line), 'E') &&
                    Char.Equals(GetChar(index, line), '+') ||
                    Char.Equals(GetChar(index, line), '-') ||
                    Char.IsDigit(GetChar(index, line)))
                             //if number has scale factor follwed by valid char
                                                     //STATE DIAGRAM BRANCH #12
                    lexeme = lexeme + GetChar(index, line);  //move e to lexeme
                    index++;                                //move to next char
                    while (index < line.Length 
                        && Char.IsDigit(GetChar(index, line)))
                    {                                        //grab more digits
                        lexeme = lexeme + GetChar(index, line); //put in lexeme
                        index++;                            //move to next char
                    }
                #endregion
                code = 2;                              //Token is a real number
            }
            else                              //if no decimals or scale factors
            {
                code = 3;                                      //must be an int
            }
            nextToken = new Token(lexeme, code, m);              //create token
            if (nextToken.TokenCode == 3)          //add to symbol table if int
            {
                nextToken.STableLoc = symbolTable.AddSymbol(lexeme, 1, 1);
                /*ERROR: Because integer values are defined in the Lexical
                 * Analyzer Specifications (Page 2, Section 2, Part b) as
                 * being allowed up to 30 characters before truncation
                 * 
                 * ""  nextToken.STableLoc = symbolTable.AddSymbol(lexeme, 
                 * 1, Convert.ToInt32(lexeme));  "" 
                 * 
                 * returns an error because
                 * given value can be greater than 2^31, making it too large
                 * to store in an "int" value.*/
            }
            else                                  //add to symbol table as real
            {
                nextToken.STableLoc = symbolTable.AddSymbol(lexeme, 1, 1);
            }
        }
        /*--------------------------------------------------------------------|
         * IsString: Takes as a parameter 1 or 2 to denote which delimiter is |
         * expected. Fills token with all elements of the string. Error if end|
         * of line is reached before string termination.                      |
         * ------------------------------------------------------------------*/
        private void IsString(int closer)
        {
            string thisString = null;         //String variable to hold parsing
           
            #region ' ' STRING DELIMITERS
            if (closer == 1)                         //string delimiter is '  '
            {
                do
                {
                    if (index == line.Length)          //if end of line reached
                    {
                        Console.WriteLine("Error: String not terminated before"
                        + "end of line\n");               //print error message
                    }
                    else                                            //otherwise
                    {
                        thisString = thisString + GetChar(index, line);
                                                                     //add char
                        index++;                        //and move to next char
                    }
                }      //while string is not terminated by the proper delimiter
                while (index < line.Length && GetChar(index, line) != '\'');
                if (index < line.Length)     //If not at end of line (no error)
                {               //add closing delimiter to the string variable.
                    thisString = thisString + GetChar(index, line);
                }
                index++;                                    //move to next char
                if (echo == true)     //if echo option is enabled, print string
                {
                    Console.WriteLine("\n  Echoing String: " + thisString + 
                        "\n");
                }
            }
            #endregion

            #region " " STRING DELIMITERS
            if (closer == 2)                         //string delimiter is "  "
            {
                do
                {
                    if (index == line.Length)          //if end of line reached
                    {
                        Console.WriteLine("Error: String not terminated before"
                        + "end of line\n");               //print error message
                    }
                    else                                            //otherwise
                    {
                        thisString = thisString + GetChar(index, line);       
                                                                     //add char
                        index++;                        //and move to next char
                    }
                }      //while string is not terminated by the proper delimiter
                while (index < line.Length && GetChar(index, line) != '\"');
                if (index < line.Length)     //If not at end of line (no error)
                {               //add closing delimiter to the string variable.
                    thisString = thisString + GetChar(index, line);
                }
                index++;                                    //move to next char
                if (echo == true)     //if echo option is enabled, print string
                {
                    Console.WriteLine("\n  Echoing String: " + thisString +
                        "\n");
                }
            }
            #endregion
            nextToken = new Token(thisString, 4, m);         //Create new token
        }
        /*--------------------------------------------------------------------|
         * IsComment: Takes as a parameter 1 or 2 to denote which delimiter is|
         * expected. Fills comment string with comment until delimiter is     |
         * reached to close the comment, getting a new line when necessary.   |
         * Gives an error if the end of file is reached before closed.        |
         * ------------------------------------------------------------------*/
        private void IsComment(int closer)
        {
            bool stillParsing = true;  //bool to check if still parsing comment
            string comment = null;     //create an empty string to hold comment
            #region { DELIMITED COMMENT
            if (closer == 1)                      //comment delimiter is '{  }'
            {
                do
                {
                    if (index == line.Length)       //if end of line is reached
                    {
                        GetLine();                          //get the next line
                        index = 0;            //and reset index to head of line
                    }
                    if (line != null && index < line.Length)
                    {                                 //if valid line and index
                        comment = comment + GetChar(index, line);  
                                                          //add char to comment
                    }
                    index++;                            //and move to next char
                }         //while line not null (EOF) and not at end of comment
                while (line != null && GetChar(index - 1, line) != '}');
                if (line != null && index < line.Length 
                    && GetChar(index, line) == '}')
                {                             //if valid comment (no EOF error)
                    comment = comment + GetChar(index, line);    
                                                        //add closer to comment
                    index++;                      //and move index to next char
                }
                if (line == null)                      //if end of file reached
                {
                    Console.WriteLine("\nError: End of File reached before" + 
                        " comment is terminated.\n");     //Print error message
                }
                stillParsing = false;           //no longer parsing the comment
            }
            #endregion

            #region (* DELIMITED COMMENT
            if (closer == 2)                      //comment delimiter is (*  *)
            {
                do
                {
                    if (line == null)                  //If end of file reached
                    {
                        stillParsing = false;               //no longer parsing
                    }
                    if (index == line.Length)          //If end of line reached
                    {
                        GetLine();                             //Get a new line
                        index = 0;                 //Move index to head of line
                        if (line == null)                 //End of file reached
                        {
                            stillParsing = false;           //no longer parsing
                            Console.WriteLine("\nError: End of File reached " + 
                                "before comment is terminated.\n"); //Error msg
                        }
                    }
                    if (stillParsing == true)                //if still parsing
                    {
                        if (index < line.Length)            //If index is valid
                        {
                            comment = comment + GetChar(index, line);         
                                                                     //add char
                            index++;                        //move to next char
                        }
                        if (index < line.Length && GetChar(index, line) == ')'
                            && GetChar(index - 1, line) == '*')      
                                                         //end of comment found
                        {
                            stillParsing = false;           //no longer parsing
                        }
                    }
                }
                while (stillParsing == true);             //while still parsing
                if (line != null && index < line.Length
                    && GetChar(index, line) == ')')
                {                                            //if line is valid
                    comment = comment + GetChar(index, line);
                                                    //add ')' to comment string
                    index++;                                //move to next char
                }
            }
            #endregion
        }
        /*--------------------------------------------------------------------|
         * GetLine: Accesses given file and reads one line at a time. Echos   |
         * line if echo is turned on, and prints an error if it cannot read   |
         * the line.                                                          |
         * ------------------------------------------------------------------*/
        private void GetLine()
        {
            if (File.Exists(this.filePath))            //If the filepath exists
            {

                try
                {
                    line = file.ReadLine();                        //reads line
                    lineNumber++;                       //Increment Line Number
                    if (echo == true)                    //if echo is turned on
                    {                                          //print the line
                        Console.WriteLine("\n  Echoing Line: " + line + "\n");
                    }
                    while (line != null && line.Length == 0) //while empty line
                    {
                        line = file.ReadLine();               //read a new line
                        lineNumber++;                       //Increment Line Number
                    }
                    if (line == null)                    //If a null line found
                    {
                        endOfFile = true;                   //found end of file
                    }
                }
                catch                                      //if file read error
                {
                    Console.WriteLine("Error with file");       //print message
                }
            }
            else                                            //if file not found
            {
                Console.WriteLine("Error: File Not Found");     //Print message
            }
        }
        /*--------------------------------------------------------------------|
         * IsEnd returns the bool showing if the reader has reached the EOF   |
         * ------------------------------------------------------------------*/
        public bool IsEnd()
        {
            return endOfFile;
        }
        /*--------------------------------------------------------------------|
         * Echo provides optional means to change the echo value in the middle|
         * of file parsing.                                                   |
         * ------------------------------------------------------------------*/
        public void Echo(bool e)
        {
            echo = e;
        }
        /*--------------------------------------------------------------------|
         * NextToken returns next token to the caller program                 |
         * ------------------------------------------------------------------*/
        public Token NextToken()
        {
            return nextToken;
        }
        /*--------------------------------------------------------------------|
         * DisplayMnem Acts as a transition function so that the main program |
         * can display Lexical's Mnemonic table.                              |
         * ------------------------------------------------------------------*/
        public void DisplayMnem()
        {
            m.Display();
        }
        /*--------------------------------------------------------------------|
         * DisplayToken displays tokens in the output. Takes a token as input.|
         * ------------------------------------------------------------------*/
        public void DisplayToken(Token token)
        {
            if (token != null)                            //if a non-null token
            {                                              //print table values
                if (token.STableLoc != -1)           //If it is in symbol table
                {
                    Console.WriteLine(token.TokenCode.ToString() + "\t"
                        + token.Mnemonic + "\t " + token.STableLoc + "\t   "
                            + token.Lexeme);
                }
                else                                   //If not in symbol table
                {
                    Console.WriteLine(token.TokenCode.ToString() + "\t"
                        + token.Mnemonic + "\t " + "  " + "\t   "
                        + token.Lexeme);
                }
            }
        }
        /*--------------------------------------------------------------------|
         * GetChar takes in an int and a string, and returns the character    |
         * found at string[int].                                              |
         * ------------------------------------------------------------------*/
        public char GetChar(int index, string str)
        {
            return str[index];
        }
        /*--------------------------------------------------------------------|
         * GetLineNumber getter method to return the line number of the       |
         * current line.                                                      |
         * ------------------------------------------------------------------*/
        public int GetLineNumber
        {
            get
            {
                return lineNumber;
            }
        }
        public string GetSourceLine
        {
            get
            {
                return line;
            }
        }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
    }
}
